#include <convert_manager.h>
#include <stdio.h>
#include <linux/videodev2.h>
#include <jpeglib.h>



/**
 * @brief 检查 V4L2 是否支持从 MJPEG 到 RGB 的格式转换
 * @param InputPixelFormat  输入格式（如 V4L2_PIX_FMT_MJPEG）
 * @param OutputPixelFormat 输出格式（如 V4L2_PIX_FMT_RGB24）
 * @return 1 支持，0 不支持
 */
int Mjpeg2Rgb_isSupport(int InputPixelFormat, int OutputPixelFormat) 
{
    if (InputPixelFormat != V4L2_PIX_FMT_MJPEG) 
    {
        fprintf(stderr, "Input format is not MJPEG!\n");
        return 0;
    }
    switch (OutputPixelFormat) 
    {
        case V4L2_PIX_FMT_RGB565:  
        case V4L2_PIX_FMT_RGB32:   
            return 1;  // 支持
        default:
            fprintf(stderr, "Output format is not RGB/BGR!\n");
            return 0;
    }
}



/**
 * @brief 将单行RGB888像素数据转换为目标RGB格式
 * @param iWidth  图像宽度
 * @param iSrcBpp 输入数据bpp
 * @param iDstBpp 输出数据bpp（需要转换成什么格式的-RGBxxx）
 * @param pudSrcDatas 输入数据指针
 * @param pudDstDatas 输出数据指针
 * @return 0 成功， -1 输入格式不支持
 */
static int ConvertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
	unsigned int dwRed;
	unsigned int dwGreen;
	unsigned int dwBlue;
	unsigned int dwColor;

	unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
	unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

	int i;
	int pos = 0;

	if (iSrcBpp != 24)
	{
		return -1;
	}

	if (iDstBpp == 24)
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			dwRed   = pudSrcDatas[pos++];
			dwGreen = pudSrcDatas[pos++];
			dwBlue  = pudSrcDatas[pos++];
			if (iDstBpp == 32)
			{
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
				*pwDstDatas32bpp = dwColor;
				pwDstDatas32bpp++;
			}
			else if (iDstBpp == 16)
			{
				/* 565 */
				dwRed   = dwRed >> 3;
				dwGreen = dwGreen >> 2;
				dwBlue  = dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
				*pwDstDatas16bpp = dwColor;
				pwDstDatas16bpp++;
			}
		}
	}
	return 0;
}


int Mjpeg2Rgb_Convert(PT_VideoBuff InputBuff, PT_VideoBuff outputBuff)
{
	struct jpeg_decompress_struct tDInfo; 
    int iRet;
    int iRowStride;
    unsigned char *aucLineBuffer = NULL;
    unsigned char *pucDest;
	T_MyErrorMgr tJerr;
    PT_PixelDatas ptPixelDatas = &ptVideoBufOut->tPixelDatas;
    
    // 设置错误处理回调
	tDInfo.err               = jpeg_std_error(&tJerr.pub);
	tJerr.pub.error_exit     = MyErrorExit;
    
    // 错误恢复点（通过setjmp实现长跳转）
	if(setjmp(tJerr.setjmp_buffer))
	{
        jpeg_destroy_decompress(&tDInfo);
        if (aucLineBuffer)
        {
            free(aucLineBuffer);
        }
        if (ptPixelDatas->aucPixelDatas)
        {
            free(ptPixelDatas->aucPixelDatas);
        }
		return -1;
	}

	jpeg_create_decompress(&tDInfo);

    jpeg_mem_src_tj (&tDInfo, ptVideoBufIn->tPixelDatas.aucPixelDatas, ptVideoBufIn->tPixelDatas.iTotalBytes);
    
    iRet = jpeg_read_header(&tDInfo, TRUE);

    tDInfo.scale_num = tDInfo.scale_denom = 1; // 禁用缩放
    	
	jpeg_start_decompress(&tDInfo);
    
	iRowStride = tDInfo.output_width * tDInfo.output_components;
	aucLineBuffer = malloc(iRowStride);

    // 内存分配失败返回-1
    if (NULL == aucLineBuffer)
    {
        return -1;
    }

    // 分配成功，设置ptPixelDatas各字段值
	ptPixelDatas->iWidth  = tDInfo.output_width;
	ptPixelDatas->iHeight = tDInfo.output_height;
	ptPixelDatas->iLineBytes    = ptPixelDatas->iWidth * ptPixelDatas->iBpp / 8;
    ptPixelDatas->iTotalBytes   = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes;
	
    // 空则映射内存
    if (NULL == ptPixelDatas->aucPixelDatas)
	{
	    ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes);
	}

    // 逐行解码与转换
    pucDest = ptPixelDatas->aucPixelDatas;
	while (tDInfo.output_scanline < tDInfo.output_height) 
	{
		(void) jpeg_read_scanlines(&tDInfo, &aucLineBuffer, 1); // 解码一行
        // 对于jpeg，bpp是24
		ConvertOneLine(ptPixelDatas->iWidth, 24, ptPixelDatas->iBpp, aucLineBuffer, pucDest);
		pucDest += ptPixelDatas->iLineBytes; // 移动指针到待处理的下一行
	}
	
    // 释放资源
	free(aucLineBuffer);
	jpeg_finish_decompress(&tDInfo);
	jpeg_destroy_decompress(&tDInfo);

    return 0;
}


int Mjpeg2Rgb_ConvertExit(PT_VideoBuff outputBuff)
{
    if (outputBuff == NULL) 
    {
        return -1; // 错误：传入空指针
    }

    // 释放RGB数据缓冲区（如果已分配）
    if (outputBuff->tPixelDatas.aucPixelDatas != NULL) 
    {
        free(outputBuff->tPixelDatas.aucPixelDatas);
        outputBuff->tPixelDatas.aucPixelDatas = NULL; // 避免悬空指针（内存被释放但指针仍然指向原地址）
    }
    return 0; // 成功释放
}


static T_ConvertOpr g_tMjpeg2Rgb = {
    .name = "Mjpeg2Rgb",
    .isSupport = Mjpeg2Rgb_isSupport,
    .Convert = Mjpeg2Rgb_Convert,
    .ConvertExit = Mjpeg2Rgb_ConvertExit,
};


void RegisterMjpeg2Rgb(void)
{
    RegisterConvertOpr(&g_tMjpeg2Rgb);
}